﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Kugar.Core.BaseStruct;
using Kugar.Core.ExtMethod;
using Kugar.Core.Network;
using Kugar.Tools.IM.Tencent.ServerSDK.Converts;
using Kugar.Tools.IM.Tencent.ServerSDK.Enums;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Kugar.Tools.IM.Tencent.ServerSDK
{
    public class TencentIMContainer
    {
        private Dictionary<uint, TencentIMApi> _cacheApi=new Dictionary<uint, TencentIMApi>();

        /// <summary>
        /// 创建一个Api管理类,并加入管理器中
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="admin"></param>
        /// <param name="privatekeyData"></param>
        /// <returns></returns>
        public  TencentIMApi Add(uint appID, string admin, string privatekeyData, uint accountType = 22208)
        {
            var api=new TencentIMApi(appID,admin,privatekeyData, accountType);

            _cacheApi.Add(appID,api);

            return api;
        }

        /// <summary>
        /// 只创建一个Api管理类,,但不加入管理器中
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="admin"></param>
        /// <param name="privatekeyData"></param>
        /// <returns></returns>
        public  TencentIMApi CreateOnly(uint appID, string admin, string privatekeyData,uint accountType= 22208)
        {
            return new TencentIMApi(appID,admin,privatekeyData, accountType);
        }

        public  TencentIMApi this[uint appID] => _cacheApi.TryGetValue(appID);


    }

    public class TencentIMApi
    {
        private long _randomMessageID = 0;

        public TencentIMApi(uint appID,string admin, string privatekeyData,uint accountType)
        {
            //UserSig = userSig ?? throw new ArgumentNullException(nameof(userSig));
            Admin = admin ?? throw new ArgumentNullException(nameof(admin));
            AppID = appID;
            PrivateKeyData = privatekeyData??throw new ArgumentNullException(nameof(privatekeyData));
            AccountType = accountType;

            UserApi = new UserApi(this);
            AccountApi = new AccountApi(this);
            GroupApi = new GroupApi(this);

            UserSig = AccountApi.GetUserSigByAccountID(admin).ReturnData;
        }
        
        public string UserSig { set; get; }

        public string Admin { set; get; }

        public uint AppID { set; get; }
        
        public string PrivateKeyData { set; get; }

        public uint AccountType { set; get; }

        public UserApi UserApi { get; private set; }

        public AccountApi AccountApi { get; private set; }

        public GroupApi GroupApi { get; private set; }


        internal JObject PostData(string url, JObject data)
        {
            const string urlStr =
                "https://console.tim.qq.com/{4}?usersig={0}&identifier={1}&sdkappid={2}&random={3}&contenttype=json";

            var json = WebHelper.Create(string.Format(urlStr, UserSig, Admin, AppID, RandomEx.NextString(6), url))
                .SetJson(data)
                .Post_Json();

            return json;
        }

        internal long GetRandomID()
        {
            return Interlocked.Increment(ref _randomMessageID);
        }

        /// <summary>
        /// 当接收到用户或群消息的时候,触发该事件,并且异步执行
        /// </summary>
        public static event MessageNotify MessageNotify;

        /// <summary>
        /// 用户在线状态变更后触发
        /// </summary>
        public static event UserOnlineStatusChanged UserOnlineStatusChanged;


        public static void ProcessNotifyMessage(DateTime triggerDt, string sdkAppID, string command, JObject json)
        {
            if (command == "C2C.CallbackAfterSendMsg" || command == "")
            {
                var fromAccount = json.GetString("From_Account");
                var toAccount = json.GetString("To_Account");

                var msgBody = json.GetJObjectArray("MsgBody");

                if (MessageNotify != null)
                {
                    MessageNotify.BeginInvoke(0, triggerDt, fromAccount,
                        toAccount,
                        msgBody.Select(x => x.ToObject<IMMessageBase>()).ToArrayEx(), EndInvoke_MessageNotify, null);
                }
            }
            else if (command == "Group.CallbackAfterSendMsg")
            {
                var fromAccount = json.GetString("From_Account");
                var toAccount = json.GetString("GroupId");

                var msgBody = json.GetJObjectArray("MsgBody");

                if (MessageNotify != null)
                {
                    MessageNotify.BeginInvoke(command == "C2C.CallbackAfterSendMsg" ? 0 : 1, triggerDt, fromAccount,
                        toAccount,
                        msgBody.Select(x => x.ToObject<IMMessageBase>()).ToArrayEx(), EndInvoke_MessageNotify, null);
                }
            }
            else if (command == "State.StateChange")
            {
                var accountID = json.GetString("To_Account");
                var action = json.GetString("Action");
                var reasonStr = json.GetString("Reason");

                if (UserOnlineStatusChanged != null)
                {
                    UserOnlineStatusChangeReasonEnum reason;

                    switch (reasonStr)
                    {
                        case "Register":
                            {
                                reason = UserOnlineStatusChangeReasonEnum.Register;
                                break;
                            }
                        case "Unregister":
                            {
                                reason = UserOnlineStatusChangeReasonEnum.Unregister;
                                break;
                            }
                        case "LinkClose":
                            {
                                reason = UserOnlineStatusChangeReasonEnum.LinkClose;
                                break;
                            }
                        case "Timeout":
                            {
                                reason = UserOnlineStatusChangeReasonEnum.Timeout;
                                break;
                            }
                        default:
                            {
                                return;
                            }
                    }

                    UserOnlineStatusChanged.BeginInvoke(accountID, action == "Login" ? true : false, reason,
                        EndInvoke_UserOnlineStatusChanged, null);
                }

            }
        }

        private static void EndInvoke_MessageNotify(IAsyncResult result)
        {
            MessageNotify.EndInvoke(result);
        }

        private static void EndInvoke_UserOnlineStatusChanged(IAsyncResult result)
        {
            UserOnlineStatusChanged.EndInvoke(result);
        }
    }


    /// <summary>
    /// 消息回调通知委托
    /// </summary>
    /// <param name="senderType">发送者类型,0=普通用户  1=群消息</param>
    /// <param name="sendDt">消息时间</param>
    /// <param name="fromAccount">发送者ID</param>
    /// <param name="toAccount">接受者ID,如果是群聊消息,则该参数固定为群ID</param>
    /// <param name="msgBody">消息实体</param>
    public delegate void MessageNotify(int senderType,DateTime sendDt,string fromAccount,string toAccount, IMMessageBase[] msgBody);

    public delegate void UserOnlineStatusChanged(string accountID, bool isOnlineNow, UserOnlineStatusChangeReasonEnum reason);

    public class UserApi
    {
        private TencentIMApi _im = null;

        internal UserApi(TencentIMApi im)
        {
            _im = im;
        }

        //public ResultReturn SendMessageToAccountID(string toAccountID,string fromAccountID="", IMMessageBase[] msgBody=null)
        //{

        //}
    }

    class dllpath
    {
        // 开发者调用 dll 时请注意项目的平台属性，下面的路径是 demo 创建时使用的，请自己使用予以修改
        // 请使用适当的平台 dll
        public const string DllPath = @"sigcheck64.dll";       // 64 位
        // 如果选择 Any CPU 平台，默认加载 32 位 dll
        //public const string DllPath = @"D:\src\oicq64\tinyid\tls_sig_api\windows\32\lib\libsigcheck\sigcheck.dll";     // 32 位
    }

    public class AccountApi
    {
        private TencentIMApi _im = null;

        internal AccountApi(TencentIMApi im)
        {
            _im = im;
        }

        public ResultReturn Import(string accountID, string nickName = "", string faceUrl = "")
        {
            if (string.IsNullOrWhiteSpace(accountID))
            {
                throw new ArgumentNullException(nameof(accountID));
            }

            var json = _im.PostData("v4/im_open_login_svc/account_import", new JObject()
                                                                           {
                                                                               ["Identifier"] = accountID,
                                                                               ["Nick"] = nickName,
                                                                               ["FaceUrl"] = faceUrl
                                                                           });

            return Until.DecodeResponse(json);
        }

        public ResultReturn Import(params ImportAccountArgs[] accounts)
        {
            if (!accounts.HasData())
            {
                return SuccessResuleReturn.Default;
            }

            var errorList = new List<ImportAccountArgs>((accounts.Length / 2).ToMinInt(2));

            ResultReturn lastErrorResult = null;

            if (accounts.Length<10)
            {
                foreach (var account in accounts)
                {
                    var ret = this.Import(account.AccountID.ToStringEx(), account.NickName.ToStringEx(), account.FaceUrl.ToStringEx());

                    if (!ret.IsSuccess)
                    {
                        errorList.Add(account);
                        lastErrorResult = ret;
                    }
                }
            }
            else
            {
                Parallel.ForEach(accounts, account =>
                {
                    var ret = this.Import(account.AccountID.ToStringEx(), account.NickName.ToStringEx(), account.FaceUrl.ToStringEx());

                    if (!ret.IsSuccess)
                    {
                        errorList.Add(account);
                        lastErrorResult = ret;
                    }
                });

            }

            if (errorList.HasData())
            {
                return new FailResultReturn($"导入{errorList.Select(x => $"{x.AccountID}").JoinToString(',')}出错;最后一次错误信息为:{lastErrorResult.Message}");
            }
            
            return SuccessResuleReturn.Default;
        }

        /// <summary>
        /// 批量导入账号ID
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        public ResultReturn Import(params string[] accountIDs)
        {
            if (!accountIDs.HasData())
            {
                throw new ArgumentNullException(nameof(accountIDs));
            }

            const string url =
                "https://console.tim.qq.com/v4/im_open_login_svc/multiaccount_import?usersig={0}&identifier={1}&sdkappid={2}&random={3}&contenttype=json";

            var json = _im.PostData("v4/im_open_login_svc/multiaccount_import", new JObject()
                                                                                {
                                                                                    ["Accounts"] = new JArray(accountIDs)
                                                                                });

            var ret = Until.DecodeResponse(json);

            if (!ret.IsSuccess)
            {
                ret.ReturnData = json.GetJArray("FailAccounts").Select(x => (string) x).ToArrayEx();
            }

            return ret;
        }



        /// <summary>
        /// 获取指定账号ID的用户签名
        /// </summary>
        /// <param name="accountID"></param>
        /// <returns></returns>
        public ResultReturn<string > GetUserSigByAccountID(string accountID)
        {
            string pri_key = _im.PrivateKeyData;

            StringBuilder sig = new StringBuilder(4096);
            StringBuilder err_msg = new StringBuilder(4096);
            int ret = tls_gen_sig_ex(
                _im.AppID,
                accountID,
                sig,
                4096,
                pri_key,
                (UInt32)pri_key.Length,
                err_msg,
                4096);

            if (0 != ret)
            {
                return new FailResultReturn<string>("生成签名错误:" + err_msg);
            }
            else
            {
                return new SuccessResuleReturn<string>(sig.ToString());
            }
        }

        [DllImport(dllpath.DllPath, EntryPoint = "tls_gen_sig", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        private static extern int tls_gen_sig(
            UInt32 expire,
            string appid3rd,
            UInt32 sdkappid,
            string identifier,
            UInt32 acctype,
            StringBuilder sig,
            UInt32 sig_buff_len,
            string pri_key,
            UInt32 pri_key_len,
            StringBuilder err_msg,
            UInt32 err_msg_buff_len
        );

        [DllImport(dllpath.DllPath, EntryPoint = "tls_vri_sig", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        private static extern int tls_vri_sig(
            string sig,
            string pub_key,
            UInt32 pub_key_len,
            UInt32 acctype,
            string appid3rd,
            UInt32 sdkappid,
            string identifier,
            StringBuilder err_msg,
            UInt32 err_msg_buff_len
        );

        [DllImport(dllpath.DllPath, EntryPoint = "tls_gen_sig_ex", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        private static extern int tls_gen_sig_ex(
            UInt32 sdkappid,
            string identifier,
            StringBuilder sig,
            UInt32 sig_buff_len,
            string pri_key,
            UInt32 pri_key_len,
            StringBuilder err_msg,
            UInt32 err_msg_buff_len
        );

        [DllImport(dllpath.DllPath, EntryPoint = "tls_vri_sig_ex", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        private static extern int tls_vri_sig_ex(
            string sig,
            string pub_key,
            UInt32 pub_key_len,
            UInt32 sdkappid,
            string identifier,
            ref UInt32 expire_time,
            ref UInt32 init_time,
            StringBuilder err_msg,
            UInt32 err_msg_buff_len
        );
    }

    public class ImportAccountArgs
    {
        public string AccountID { set; get; }

        public string NickName { set; get; }

        public string FaceUrl { set; get; }
    }

    /// <summary>
    /// 群聊
    /// </summary>
    public class GroupApi
    {
        private TencentIMApi _im = null;
        private int _randomID = 0;

        internal GroupApi(TencentIMApi im)
        {
            _im = im;
        }

        /// <summary>
        /// 新增一个群,并返回群ID
        /// </summary>
        /// <param name="type">群类型</param>
        /// <param name="groupName">群名称</param>
        /// <param name="ownerAccountID">群主ID(可选)</param>
        /// <param name="memberAccountIDs">群成员ID(可选)</param>
        /// <param name="groupId">自定义群ID(可选)</param>
        /// <param name="faceUrl">群Logo(可选)</param>
        /// <param name="maxMemberCount">群最大人数(可选)</param>
        /// <param name="introduction">群简介(可选)</param>
        /// <param name="notification">群公告(可选)</param>
        /// <param name="applyJoinOption">申请加群的方式(可选),默认为:NeedPermission</param>
        /// <param name="appDefinedData">群自定义数据(可选)</param>
        /// <returns></returns>
        public ResultReturn<string> Create(GroupTypeEnum type,
            string groupName,
            string ownerAccountID = "",
            string[] memberAccountIDs = null,
            string groupId = "",
            string faceUrl = "",
            int maxMemberCount = -1,
            string introduction = "",
            string notification = "",
            JoinGroupTypeEnum applyJoinOption = JoinGroupTypeEnum.NeedPermission,
            KeyValuePair<string, string>[] appDefinedData = null
        )
        {
            var args = new JObject()
                       {
                           ["Name"] = groupName,
                           ["Type"] = type.ToString(),
                           ["ApplyJoinOption"] = applyJoinOption.ToStringEx()
                       };

            if (!string.IsNullOrWhiteSpace(ownerAccountID))
            {
                args.Add("Owner_Account", ownerAccountID);
            }

            if (!string.IsNullOrWhiteSpace(groupId))
            {
                args.Add("GroupId", groupId);
            }

            if (!string.IsNullOrWhiteSpace(faceUrl))
            {
                args.Add("FaceUrl", faceUrl);
            }

            if (maxMemberCount > 0)
            {
                args.Add("MaxMemberCount", maxMemberCount);
            }

            if (memberAccountIDs.HasData())
            {
                args.Add("MemberList", new JArray(memberAccountIDs.Select(x=>new JObject()
                                                    {
                                                        ["Member_Account"]=x
                                                    })));
                //args.Add(new JArray(memberAccountIDs));
            }

            if (!string.IsNullOrWhiteSpace(introduction))
            {
                args.Add("Introduction", introduction);
            }

            if (!string.IsNullOrWhiteSpace(notification))
            {
                args.Add("Notification", notification);
            }

            if (appDefinedData.HasData())
            {
                args.Add("AppDefinedData", new JArray(appDefinedData.Select(x => new JObject()
                                                                                 {
                                                                                     ["Key"] = x.Key,
                                                                                     ["Value"] = x.Value
                                                                                 })));
            }

            var json = _im.PostData("v4/group_open_http_svc/create_group", args);

            var ret = Until.DecodeResponse(json);

            return ret.Cast(json.GetString("GroupId"), "");
        }

        /// <summary>
        /// 修改群信息
        /// </summary>
        /// <param name="groupID">群ID</param>
        /// <param name="groupName">群名称</param>
        /// <param name="faceUrl">群Logo(可选)</param>
        /// <param name="maxMemberCount">群最大人数(可选)</param>
        /// <param name="introduction">群简介(可选)</param>
        /// <param name="notification">群公告(可选)</param>
        /// <param name="applyJoinOption">申请加群的方式(可选),默认为:NeedPermission</param>
        /// <param name="appDefinedData">群自定义数据(可选)</param>
        /// <returns></returns>
        public ResultReturn Update(string groupID,
            string groupName,
            string faceUrl = "",
            int maxMemberCount = -1,
            string introduction = "",
            string notification = "",
            JoinGroupTypeEnum applyJoinOption = JoinGroupTypeEnum.NeedPermission,
            KeyValuePair<string, string>[] appDefinedData = null
        )
        {
            var args = new JObject()
                       {
                           ["Name"] = groupName,
                           ["ApplyJoinOption"] = applyJoinOption.ToStringEx()
                       };

            if (!string.IsNullOrWhiteSpace(faceUrl))
            {
                args.Add("FaceUrl", faceUrl);
            }

            if (maxMemberCount > 0)
            {
                args.Add("MaxMemberCount", maxMemberCount);
            }

            if (appDefinedData.HasData())
            {
                args.Add("AppDefinedData", new JArray(appDefinedData.Select(x => new JObject()
                                                                                 {
                                                                                     ["Key"] = x.Key,
                                                                                     ["Value"] = x.Value
                                                                                 })));
            }

            if (!string.IsNullOrWhiteSpace(introduction))
            {
                args.Add("Introduction", introduction);
            }

            if (!string.IsNullOrWhiteSpace(notification))
            {
                args.Add("Notification", notification);
            }

            var json = _im.PostData("v4/group_open_http_svc/modify_group_base_info", args);

            var ret = Until.DecodeResponse(json);

            return ret;
        }

        /// <summary>
        /// 获取指定ID群信息
        /// </summary>
        /// <param name="groupID"></param>
        /// <returns></returns>
        public ResultReturn<GroupInfo> GetGroupInfoByID(string groupID)
        {
            var json = _im.PostData("v4/group_open_http_svc/get_group_info"
                , new JObject()
                  {
                      ["GroupIdList"] = new JArray() {groupID}
                  });

            var ret = Until.DecodeResponse(json);

            return ret.Cast(decodeGroupInfo(json.GetJObjectArray("GroupInfo").FirstOrDefault()), null);
        }

        /// <summary>
        /// 添加账号
        /// </summary>
        /// <param name="groupID"></param>
        /// <param name="accountIDs"></param>
        /// <param name="isSilence"></param>
        /// <returns></returns>
        public ResultReturn AddAccountToGroup(string groupID, string[] accountIDs, bool isSilence = false)
        {
            if (string.IsNullOrWhiteSpace(groupID))
            {
                throw new ArgumentNullException(nameof(groupID));
            }

            if (!accountIDs.HasData())
            {
                throw new ArgumentNullException(nameof(accountIDs));
            }

            var json = _im.PostData("v4/group_open_http_svc/add_group_member",
                new JObject()
                {
                    ["GroupId"] = groupID,
                    ["Silence"] = isSilence ? 1 : 0,
                    ["MemberList"] = new JArray(accountIDs.Select(x => new JObject()
                                                                       {
                                                                           ["Member_Account"] = x
                                                                       }))
                });

            var ret = Until.DecodeResponse(json);

            return ret;
        }

        /// <summary>
        /// 从指定群里商户指定账号ID列表
        /// </summary>
        /// <param name="groupID"></param>
        /// <param name="accountIDs"></param>
        /// <param name="isSilence"></param>
        /// <param name="reason"></param>
        /// <returns></returns>
        public ResultReturn DeleteAccountFromGroup(string groupID, string[] accountIDs, bool isSilence = false,
            string reason = "")
        {
            if (string.IsNullOrWhiteSpace(groupID))
            {
                throw new ArgumentNullException(nameof(groupID));
            }

            if (!accountIDs.HasData())
            {
                throw new ArgumentNullException(nameof(accountIDs));
            }

            var json = _im.PostData("v4/group_open_http_svc/add_group_member",
                new JObject()
                {
                    ["GroupId"] = groupID,
                    ["Silence"] = isSilence ? 1 : 0,
                    ["Reason"] = reason,
                    ["MemberToDel_Account"] = new JArray(accountIDs)
                });

            var ret = Until.DecodeResponse(json);

            return ret;
        }

        /// <summary>
        /// 删除一个群
        /// </summary>
        /// <param name="groupID"></param>
        /// <returns></returns>
        public ResultReturn DeleteGroup(string groupID)
        {
            if (string.IsNullOrWhiteSpace(groupID))
            {
                throw new ArgumentNullException(nameof(groupID));
            }

            var json = _im.PostData("v4/group_open_http_svc/destroy_group",
                new JObject()
                {
                    ["GroupId"] = groupID
                });

            var ret = Until.DecodeResponse(json);

            return ret;
        }

        /// <summary>
        /// 修改群的群主
        /// </summary>
        /// <param name="groupID"></param>
        /// <param name="newOwnerAccountID"></param>
        /// <returns></returns>
        public ResultReturn SetOwnerAccount(string groupID, string newOwnerAccountID)
        {
            if (string.IsNullOrWhiteSpace(groupID))
            {
                throw new ArgumentNullException(nameof(groupID));
            }

            if (!string.IsNullOrWhiteSpace(newOwnerAccountID))
            {
                throw new ArgumentNullException(nameof(newOwnerAccountID));
            }

            var json = _im.PostData("v4/group_open_http_svc/change_group_owner",
                new JObject()
                {
                    ["GroupId"] = groupID,
                    ["NewOwner_Account"] = newOwnerAccountID
                });

            var ret = Until.DecodeResponse(json);

            return ret;
        }

        /// <summary>
        /// 获取指定账号ID用户所加入的群信息
        /// </summary>
        /// <param name="accountID"></param>
        /// <param name="fields">显示的字段名称</param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public VM_PagedList<GroupInfo> QueryGroupInfoByAccountID(string accountID, string[] fields,
            GroupTypeEnum? type = null, int pageIndex = 1, int pageSize = 20)
        {
            if (string.IsNullOrWhiteSpace(accountID))
            {
                throw new ArgumentNullException(nameof(accountID));
            }

            var args = new JObject()
                       {
                           ["Member_Account"] = accountID,
                           ["Limit"] = pageSize,
                           ["Offset"] = (pageIndex - 1) * pageSize
                       };

            if (type != null)
            {
                args.Add("GroupType", type.Value.ToString());
            }

            args.Add("ResponseFilter", new JObject()
                                       {
                                           ["GroupBaseInfoFilter"] = new JArray()
                                                                     {
                                                                         "Type",
                                                                         "Name",
                                                                         "Introduction",
                                                                         "Notification",
                                                                         "FaceUrl",
                                                                         "CreateTime",
                                                                         "Owner_Account",
                                                                         "LastInfoTime",
                                                                         "LastMsgTime",
                                                                         "NextMsgSeq",
                                                                         "MemberNum",
                                                                         "MaxMemberNum",
                                                                         "ApplyJoinOption",
                                                                         "ShutUpAllMember"
                                                                     }
                                       });

            var json = _im.PostData("v4/group_open_http_svc/get_joined_group_list", args);

            var ret = Until.DecodeResponse(json);

            if (ret)
            {
                return new VM_PagedList<GroupInfo>(json.GetJObjectArray("GroupIdList").Select(decodeGroupInfo),
                    pageIndex, pageSize, json.GetInt("TotalCount"));
            }
            else
            {
                return VM_PagedList<GroupInfo>.Empty(pageIndex, pageSize);
            }
        }

        /// <summary>
        /// 获取指定账号ID用户所加入的群ID
        /// </summary>
        /// <param name="accountID"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public VM_PagedList<string> QueryGroupIDByAccountID(string accountID, GroupTypeEnum? type = null,
            int pageIndex = 1, int pageSize = 20)
        {
            if (string.IsNullOrWhiteSpace(accountID))
            {
                throw new ArgumentNullException(nameof(accountID));
            }

            var args = new JObject()
                       {
                           ["Member_Account"] = accountID,
                           ["Limit"] = pageSize,
                           ["Offset"] = (pageIndex - 1) * pageSize
                       };

            if (type != null)
            {
                args.Add("GroupType", type.Value.ToString());
            }

            var json = _im.PostData("v4/group_open_http_svc/get_joined_group_list", args);

            var ret = Until.DecodeResponse(json);

            if (ret)
            {
                return new VM_PagedList<string>(json.GetJObjectArray("GroupIdList").Select(x => x.GetString("GroupId")),
                    pageIndex, pageSize, json.GetInt("TotalCount"));
            }
            else
            {
                return VM_PagedList<string>.Empty(pageIndex, pageSize);
            }
        }

        /// <summary>
        /// 发送消息到指定群中,使用管理员身份
        /// </summary>
        /// <param name="groupID"></param>
        /// <param name="msgBody"></param>
        /// <returns></returns>
        public ResultReturn SendMessageToGroup(string groupID, params IMMessageBase[] msgBody)
        {
            if (string.IsNullOrWhiteSpace(groupID))
            {
                throw new ArgumentNullException(nameof(groupID));
            }

            if (!msgBody.HasData())
            {
                throw new ArgumentOutOfRangeException(nameof(msgBody));
            }

            var json = _im.PostData("v4/group_open_http_svc/change_group_owner",
                new JObject()
                {
                    ["GroupId"] = groupID,
                    ["Random"] = _im.GetRandomID().ToString("D5"),
                    ["MsgBody"] = new JArray(msgBody.Select(JObject.FromObject)),
                    ["OfflinePushInfo"] = new JObject()
                                          {
                                              ["PushFlag"] = 0,
                                          }
                });

            return Until.DecodeResponse(json);
        }

        /// <summary>
        /// 使用指定账号ID的身份向群发送一条消息
        /// </summary>
        /// <param name="groupID"></param>
        /// <param name="fromAccountID"></param>
        /// <param name="msgBody"></param>
        /// <returns></returns>
        public ResultReturn SendMessageToGroup(string groupID, string fromAccountID, params IMMessageBase[] msgBody)
        {
            if (string.IsNullOrWhiteSpace(groupID))
            {
                throw new ArgumentNullException(nameof(groupID));
            }

            if (!msgBody.HasData())
            {
                throw new ArgumentOutOfRangeException(nameof(msgBody));
            }

            var json = _im.PostData("v4/group_open_http_svc/change_group_owner",
                new JObject()
                {
                    ["GroupId"] = groupID,
                    ["From_Account"] = fromAccountID,
                    ["Random"] = _im.GetRandomID().ToString("D5"),
                    ["MsgBody"] = new JArray(msgBody.Select(JObject.FromObject)),
                    ["OfflinePushInfo"] = new JObject()
                                          {
                                              ["PushFlag"] = 0,
                                          }
                });

            return Until.DecodeResponse(json);
        }

        private GroupTypeEnum getTypeByName(string type)
        {
            switch (type)
            {
                case "Public":
                {
                    return GroupTypeEnum.Public;
                }
                case "Private":
                {
                    return GroupTypeEnum.Private;
                }
                case "ChatRoom":
                {
                    return GroupTypeEnum.ChatRoom;
                }
                default:
                {
                    throw new ArgumentOutOfRangeException(nameof(type));
                }
            }
        }

        private JoinGroupTypeEnum getJoinGrouType(string type)
        {
            switch (type)
            {
                case "FreeAccess":
                {
                    return JoinGroupTypeEnum.FreeAccess;
                }
                case "NeedPermission":
                {
                    return JoinGroupTypeEnum.NeedPermission;
                }
                case "DisableApply":
                {
                    return JoinGroupTypeEnum.DisableApply;
                }
                default:
                {
                    throw new ArgumentOutOfRangeException(nameof(type));
                }
            }
        }

        private GroupInfo decodeGroupInfo(JObject json)
        {
            if (json == null)
            {
                return null;
            }
            else
            {
                if (json.TryGetValue("ErrorCode", out JToken value))
                {
                    if ((int) value != 0)
                    {
                        return null;
                    }
                }

                var group = new GroupInfo()
                            {
                                GroupID = json.GetString("GroupId"),
                                Type = getTypeByName(json.GetString("Type")),
                                Name = json.GetString("Name"),
                                Introduction = json.GetString("Introduction"),
                                Notification = json.GetString("Notification"),
                                FaceUrl = json.GetString("FaceUrl"),
                                Owner_Account = json.GetString("Owner_Account"),
                                MemberNum = json.GetInt("MemberNum"),
                                MaxMemberNum = json.GetInt("MaxMemberNum"),
                                ApplyJoinOption = getJoinGrouType(json.GetString("ApplyJoinOption")),
                                ShutUpAllMember = json.GetString("ShutUpAllMember") == "On",
                                AppDefinedData = json.GetJObjectArray("AppDefinedData") == null
                                    ? json.GetJObjectArray("AppDefinedData").Select(x =>
                                            new KeyValuePair<string, string>(x.GetString("Key"), x.GetString("Value")))
                                        .ToArrayEx()
                                    : null
                            };

                return group;
            }
        }
    }

    

    public class GroupInfo
    {
        public string GroupID { set; get; }

        public string Name { set; get; }

        public GroupTypeEnum Type { set; get; }

        public string Introduction { set; get; }

        public string Notification { set; get; }

        public string FaceUrl { set; get; }

        public string Owner_Account { set; get; }

        public int MemberNum { set; get; }


        public int MaxMemberNum { set; get; }

        public JoinGroupTypeEnum ApplyJoinOption { set; get; }

        public KeyValuePair<string, string>[] AppDefinedData { set; get; }

        public bool ShutUpAllMember { set; get; }
    }

    public static class Until
    {
        internal static ResultReturn DecodeResponse(JObject json)
        {
            if (json.GetString("ActionStatus") == "OK")
            {
                return SuccessResuleReturn.Default;
            }
            else
            {
                return new ResultReturn(false, null, message: json.GetString("ErrorInfo"),
                    returnCode: json.GetInt("ErrorCode"));
            }
        }

        internal static bool IsResponseSuccess(JObject json)
        {
            if (json.GetString("ActionStatus") == "OK")
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static string GetMessageTypeStr(MessageItemTypeEnum type)
        {
            switch (type)
            {
                case MessageItemTypeEnum.Text:
                    return "TIMTextElem";
                case MessageItemTypeEnum.Face:
                    return "TIMFaceElem";
                case MessageItemTypeEnum.Image:
                    return "TIMImageElem";
                case MessageItemTypeEnum.Sound:
                    return "TIMSoundElem";
                case MessageItemTypeEnum.Custom:
                    return "TIMCustomElem";
                case MessageItemTypeEnum.Location:
                    return "TIMLocationElem";
                case MessageItemTypeEnum.File:
                    return "TIMFileElem";
                default:
                    throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
        }

        public static MessageItemTypeEnum GetMessageTypeFromStr(string typeStr)
        {
            switch (typeStr)
            {
                case "TIMTextElem":
                    return MessageItemTypeEnum.Text;
                case "TIMFaceElem":
                    return MessageItemTypeEnum.Face;
                case "TIMImageElem":
                    return MessageItemTypeEnum.Image;
                case "TIMSoundElem":
                    return MessageItemTypeEnum.Sound;
                case "TIMCustomElem":
                    return MessageItemTypeEnum.Custom;
                case "TIMLocationElem":
                    return MessageItemTypeEnum.Location;
                case "TIMFileElem":
                    return MessageItemTypeEnum.File;
                default:
                    throw new ArgumentOutOfRangeException(nameof(typeStr), typeStr, null);
            }
        }
    }
}